extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}

#include <opencv2/opencv.hpp>
#include <iostream>

void dump_hex(const char *discript, const char *data, int size) {
  if (discript) {
    fprintf(stderr, "%s ", discript);
  }

  for (int i = 0; i < size; i++) {
    fprintf(stderr, "%02x ", (unsigned char)data[i]);
  }
  fprintf(stderr, "\n");
}

int main() {
  //const char *vdo_url = "rtsp://192.168.6.85:8557/h264";
  const char *vdo_url = "E:\\source\\cmake_sample\\pack\\bin\\14_9_1.avi";

  // 初始化 FFmpeg
  avformat_network_init(); // 初始化网络

  // 打开输入文件
  AVFormatContext* formatCtx = nullptr;
  if (avformat_open_input(&formatCtx, vdo_url, nullptr, nullptr) < 0) {
    std::cerr << "Could not open input file." << std::endl;
    return -1;
  }

  // 查找流信息
  if (avformat_find_stream_info(formatCtx, nullptr) < 0) {
    std::cerr << "Could not find stream information." << std::endl;
    return -1;
  }

  // 查找视频流
  int videoStreamIndex = -1;
  for (int i = 0; i < formatCtx->nb_streams; ++i) {
    if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
      videoStreamIndex = i;
      break;
    }
  }

  if (videoStreamIndex == -1) {
    std::cerr << "Could not find video stream." << std::endl;
    return -1;
  }

  // 查找解码器
  AVCodecParameters* codecParams = formatCtx->streams[videoStreamIndex]->codecpar;
  const AVCodec* codec = avcodec_find_decoder(codecParams->codec_id);
  if (!codec) {
    std::cerr << "Unsupported codec." << std::endl;
    return -1;
  }

  AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
  if (!codecCtx) {
    std::cerr << "Could not allocate codec context." << std::endl;
    return -1;
  }

  if (avcodec_parameters_to_context(codecCtx, codecParams) < 0) {
    std::cerr << "Could not copy codec parameters to context." << std::endl;
    return -1;
  }

  if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
    std::cerr << "Could not open codec." << std::endl;
    return -1;
  }

  // 创建 OpenCV 窗口
  std::string win_name = "AVI video"; // OpenCV 窗口的名称
  cv::namedWindow(win_name, cv::WINDOW_AUTOSIZE);

  AVPacket packet;
  AVFrame* frame = av_frame_alloc(); // 读取视频帧

  // 创建一个 YUV 图像（这里使用随机数据作为示例）
  cv::Mat yuv_img(codecCtx->height + codecCtx->height / 2, codecCtx->width, CV_8UC1, cv::Scalar(0));

  // 创建一个 RGB 图像用于显示
  cv::Mat rgb_img(codecCtx->height, codecCtx->width, CV_8UC3);

  while (av_read_frame(formatCtx, &packet) >= 0) {
    if (packet.stream_index == videoStreamIndex) {
      int response = avcodec_send_packet(codecCtx, &packet);
      if (response < 0) {
        std::cerr << "Error sending packet for decoding." << std::endl;
        break;
      }

      while (response >= 0) {
        response = avcodec_receive_frame(codecCtx, frame);
        if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
          break;
        } else if (response < 0) {
          std::cerr << "Error during decoding." << std::endl;
          return -1;
        }

        for (int i = 0; i < frame->nb_side_data; ++i) {
          AVFrameSideData *side_data = frame->side_data[i];
          if (side_data->type == AV_FRAME_DATA_SEI_UNREGISTERED) {
            // 此时 side_data->data 指向非注册的 SEI 数据；
//            uint8_t *sei_data = side_data->data;
//            int sei_size = side_data->size;
            dump_hex("sei info:", (const char *) side_data->data, side_data->size);

            unsigned char data[12] = {0};
            memcpy(data, side_data->data + side_data->size - 12, 12);
            printf("sei info: %d cm \n", ((int)data[4]<<8 | data[3]));
          }
        }
      }
    }
    av_packet_unref(&packet);
  }

  // 清理
  av_frame_free(&frame);
  avcodec_free_context(&codecCtx);
  avformat_close_input(&formatCtx);
  cv::destroyAllWindows();

  return 0;
}